/**
 * 
 */
package cn.springsoter.core.security.strategy.impl;

import java.io.FileNotFoundException;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.google.common.collect.Maps;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.springsoter.core.security.constant.SecurityConstant;
import cn.springsoter.core.security.props.SecurityProperties;
import cn.springsoter.core.security.strategy.ReadKeyStrategy;
import cn.springsoter.core.tool.utils.FileUtil;
import cn.springsoter.core.tool.utils.KeyStoreUtil;
import cn.springsoter.core.tool.utils.SpringUtil;

/**
 * 从keystore读取SM key
 * 
 * @author kevin
 *
 */
@Service
public class ReadSMKeyStoreStrategy implements ReadKeyStrategy {

	private static final String SM_KEY_STORE_CACHE = "SM_KEY_STORE";
	private static Map<String, String> KEY_MAP = Maps.newConcurrentMap();
	private static Map<String, SM2> SM2_MAP = Maps.newConcurrentMap();
	
	/**
	 * 获取SM4的明文key
	 * 
	 */
	@Override
	public synchronized String readKey() throws Exception{
		String key = KEY_MAP.get(SM_KEY_STORE_CACHE);
		SM2 sm2 = SM2_MAP.get(SM_KEY_STORE_CACHE);
		if(StringUtils.isBlank(key)) {
			SecurityProperties securityProperties = null;
			try {
				securityProperties = SpringUtil.getBean("securityProperties");
			} catch(Exception e) {
			}
			
			if(Objects.nonNull(securityProperties) 
					&& StringUtils.isNotBlank(securityProperties.getPassword()) 
					&& StringUtils.isNotBlank(securityProperties.getAppName())
					&& StringUtils.isNotBlank(securityProperties.getKeystorePath())) { //先判断keystore是否有密钥
				
				String sm4Alias = String.format(SecurityConstant.SM4_ALIAS, securityProperties.getAppName());
				String sm2PrivateAlias = String.format(SecurityConstant.SM2_PRIVATE_ALIAS, securityProperties.getAppName());
				String sm2PublicAlias = String.format(SecurityConstant.SM2_PUBLIC_ALIAS, securityProperties.getAppName());
				
				String sm4Path = String.format(SecurityConstant.KEYSTORE_PATH, securityProperties.getKeystorePath(), sm4Alias);
				String privateKeyPath = String.format(SecurityConstant.KEYSTORE_PATH, securityProperties.getKeystorePath(), sm2PrivateAlias);
				String publicKeyPath = String.format(SecurityConstant.KEYSTORE_PATH, securityProperties.getKeystorePath(), sm2PublicAlias);
				
				if(!FileUtil.exist(sm4Path) || !FileUtil.exist(privateKeyPath) || !FileUtil.exist(publicKeyPath)) {
		    		throw new FileNotFoundException("file: SM KeyStore file not exist!");
		    	}
				
				String privateKey = KeyStoreUtil.getStoreKey(sm2PrivateAlias, privateKeyPath, securityProperties.getPassword());
				String publicKey = KeyStoreUtil.getStoreKey(sm2PublicAlias, publicKeyPath, securityProperties.getPassword());
				String sm4Key = KeyStoreUtil.getStoreKey(sm4Alias, sm4Path, securityProperties.getPassword());
				
				if(Objects.isNull(sm2)) {
					sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey));
					SM2_MAP.put(SM_KEY_STORE_CACHE, sm2);
				}
				
				if(Objects.nonNull(sm2)) {
					// 用SM2的私钥解密SM4的key
					key = sm2.decryptStr(sm4Key, KeyType.PrivateKey, CharsetUtil.CHARSET_UTF_8);
					KEY_MAP.put(SM_KEY_STORE_CACHE, key);
				}
			}
		}
		return key;
	}
	
	/**
	 * 获取SM2实例对象
	 * 
	 * @return
	 * @throws Exception 
	 */
	public synchronized SM2 getSm2Instance() throws Exception{
		SM2 sm2 = SM2_MAP.get(SM_KEY_STORE_CACHE);
		if(Objects.nonNull(sm2)) {
			return sm2;
		}
		
		SecurityProperties securityProperties = null;
		try {
			securityProperties = SpringUtil.getBean("securityProperties");
		} catch(Exception e) {
		}
		
		if(Objects.nonNull(securityProperties) 
				&& StringUtils.isNotBlank(securityProperties.getPassword()) 
				&& StringUtils.isNotBlank(securityProperties.getAppName())
				&& StringUtils.isNotBlank(securityProperties.getKeystorePath())) { //先判断keystore是否有密钥
			
			String sm2PrivateAlias = String.format(SecurityConstant.SM2_PRIVATE_ALIAS, securityProperties.getAppName());
			String sm2PublicAlias = String.format(SecurityConstant.SM2_PUBLIC_ALIAS, securityProperties.getAppName());
			
			String privateKeyPath = String.format(SecurityConstant.KEYSTORE_PATH, securityProperties.getKeystorePath(), sm2PrivateAlias);
			String publicKeyPath = String.format(SecurityConstant.KEYSTORE_PATH, securityProperties.getKeystorePath(), sm2PublicAlias);
			
			if(!FileUtil.exist(privateKeyPath) || !FileUtil.exist(publicKeyPath)) {
	    		throw new FileNotFoundException("file: SM KeyStore file not exist!");
	    	}
			
			String privateKey = KeyStoreUtil.getStoreKey(sm2PrivateAlias, privateKeyPath, securityProperties.getPassword());
			String publicKey = KeyStoreUtil.getStoreKey(sm2PublicAlias, publicKeyPath, securityProperties.getPassword());
			
			sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey));
			//放入缓存
			SM2_MAP.put(SM_KEY_STORE_CACHE, sm2);
		}
		
		return sm2;
	}

}
